# -*- coding: utf-8 -*-
# created on 2016/8/2

import re
from sympy import Symbol
from mathsolver.functions.shuyushi.shuyushi import DaiRu
from mathsolver.functions.root.jiefangchen import JieFangChen
from mathsolver.functions.base import (BaseFunction, BaseFunc, BaseEq, BaseVariable, BaseSymbolValue, BaseIneq,
                                       BaseFuncName, BaseSinFunc, BasePoly, BaseNumber, new_latex)
from mathsolver.functions.basic import Filter
from mathsolver.functions.sympy_utils import get_all_child


class HanShuCompute(BaseFunction):
    def solver(self, *args):
        if isinstance(args[0], BaseFuncName):
            funcname = args[0]
            func = self.search(funcname.name)
        else:
            func = args[0]
            funcname = func

        if not isinstance(func, (BaseFunc, BaseSinFunc)):
            if self.known['func_equations'] and self.known['func_assign']:
                from mathsolver.functions.hanshu.hanshu_inference import solve_hanshu_qiuzhi
                result, steps = solve_hanshu_qiuzhi(list(set(self.known['func_equations'])), self.known['func_assign'], funcname.var)
                self.steps.extend(steps)
                self.output.append(BaseNumber(result))
                self.label.add("函数的性质综合求值")
                return self
            elif self.known['func_piecewise'] and self.known['func_equations']:
                from mathsolver.functions.hanshu.jiou_qiujiexishi import JiOuJieXiShi
                from mathsolver.functions.hanshu.zhonghe_qiuzhi import ZhongHeQiuZhi
                piecewise = self.known["func_piecewise"][0]
                if funcname.var.free_symbols:
                    stepsolver = JiOuJieXiShi().solver(self.known['func_equations'][0], piecewise[0], BaseFunc({"name": funcname.name, "type": "", "expression": piecewise[2], "var": funcname.var}))
                    self.steps.extend(stepsolver.steps)
                    self.output.append(stepsolver.output[0])
                else:
                    func_equations = list(set(self.known['func_equations']))
                    func_equations = func_equations[0] if len(func_equations) == 1 else func_equations
                    stepsolver = ZhongHeQiuZhi().solver(func_equations, piecewise[0], BaseFunc({"name": funcname.name, "type": "", "expression": piecewise[2], "var": piecewise[1]}), funcname)
                    result, steps = stepsolver.output[0].value, stepsolver.steps
                    self.steps.extend(steps)
                    self.output.append(BaseNumber(result))
                    self.label.add("函数的性质综合求值")
                return self
        sub_func = get_all_child(funcname.var, lambda x: "__" in x.__class__.__name__)
        for sub in sub_func:
            name, var = str(sub).split("__", 1)
            var = re.search("\\((.*)\\)", var).group(1)
            stepsolver = HanShuCompute(known=self.known).solver(BaseFuncName({"name": name, "var": var, "type": type}))
            self.steps.extend(stepsolver.steps)
            funcname.var = funcname.var.subs({sub: stepsolver.output[0].value})
        # 补充：分段函数代入求值：f( 2*f( 1-f(a) ) )
        if isinstance(func.expression, list):
            value = func.run(funcname.var)
            self.steps.append(["", "%s = %s" % (funcname.printing(), new_latex(value))])
            if funcname.name in str(value):
                return self.solver(BaseFuncName({'var': value.args[0], 'type': '', 'name': funcname.name}), func)
            answer = BasePoly(value)
        elif len(funcname.var.free_symbols) == 0:
            if funcname.type == "inverse":
                assert func.var.is_Symbol
                stepsolver = JieFangChen().solver(BaseEq([funcname.var, func.expression]))
                self.steps.extend(stepsolver.steps)
                answer = stepsolver.output[0]
                for cond in func.cond:
                    if isinstance(cond, BaseIneq):
                        stepsolver = Filter().solver(answer, cond)
                        self.steps.extend(stepsolver.steps)
                        answer = stepsolver.output[0]

                self.steps.append(["", "%s = %s" % (funcname.printing(), answer.printValue())])
            elif len(func.expression.free_symbols) == 1 or len(func.values) == 0:
                if not func.var.is_Symbol:
                    stepsolver = JieFangChen().solver(BaseEq([funcname.var, func.var]))
                    self.steps.extend(stepsolver.steps)
                    answer = stepsolver.output[0]
                else:
                    symbol = func.var.free_symbols.pop()
                    answer = BaseSymbolValue({symbol: [funcname.var]})

                stepsolver = DaiRu().solver(BasePoly(func.expression), answer)
                answer = stepsolver.output[0]
                self.steps.extend(stepsolver.steps)
                self.steps.append(["", "%s = %s" % (funcname.printing(), answer.printing())])
                self.label.add("代入法求函数值")
            elif func.var.is_Symbol:
                values = [(func.expression.subs({func.var: k}), "%s(%s)" % (func.name, new_latex(k)), v) for k, v in
                          func.values.items()]  # known value f(5)=1 => [5a + 25b + 2, f(5) 1]
                value = func.expression.subs({func.var: funcname.var})  # unknown value f(-5) => => [-5a - 25b + 2, 1]
                for k, name, v in values:
                    if len((value + k).simplify().free_symbols) == 0:
                        answer = k + value - v
                        self.steps.append(["%s + %s = %s" % (funcname.printing(), name, new_latex(value + k)),
                                           "%s = %s" % (funcname.printing(), new_latex(answer))])
                    elif len((value - k).simplify().free_symbols) == 0:
                        answer = k + value + v
                        self.steps.append(["%s - %s = %s" % (funcname.printing(), name, new_latex(value - k)),
                                           "%s = %s" % (funcname.printing(), new_latex(answer))])
                answer = BaseNumber(answer)
            else:
                raise ValueError
        else:
            if funcname.type == "inverse":
                raise ValueError()
            else:
                if not func.var.is_Symbol:
                    stepsolver = HanShuNormalize().solver(func)
                    self.steps.extend(stepsolver.steps)
                    func = stepsolver.output[0]
                if str(funcname.var) == str(func.var):
                    self.steps.append(["", func.printing()])
                    answer = BasePoly(func.expression)
                else:
                    answer = BaseSymbolValue({func.var: [funcname.var]})
                    stepsolver = DaiRu().solver(BasePoly(func.expression), answer)
                    answer = stepsolver.output[0]
                    if not funcname.var.is_Symbol:
                        self.steps.extend(stepsolver.steps)
                    self.steps.append(["", "%s = %s" % (funcname.printing(), answer.printing())])
                self.label.add("代入法求函数解析式")
        self.output.append(answer)
        return self


class HanShuNormalize(BaseFunction):
    def solver(self, *args):
        func = args[0]
        t = Symbol('t')
        symbol = func.var.free_symbols.pop()
        self.steps.append(["", "令%s = %s, 得" % (new_latex(func.var), t)])
        stepsolver = JieFangChen().solver(BaseEq([func.var, t]), BaseVariable(symbol))
        symbol_value = stepsolver.output[0].value
        self.steps.append(["", self.output_answer(symbol_value)])
        res = DaiRu().solver(BasePoly(func.expression), BaseSymbolValue(symbol_value))
        self.steps.append(["", "所以，f(t) "])
        self.steps += res.steps[1:]
        func.var = t
        func.expression = res.output[0].value
        self.output.append(func)
        return self


if __name__ == '__main__':
    pass
